﻿using System.IO;
using System.Linq;
using PSE.Deployment.Engine;
using PSE.Deployment.Engine.Enums;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.Util;
using PSE.Deployment.SetupBase.Configuration;
using System;
using System.Collections.Generic;
using PSE.Deployment.SetupBase.Parameter;

namespace PSE.Deployment.SetupBase.Steps
{
    public class SaveInstallationInformation : SetupStep<Configuration.Actions.UpdateWindowsRegistry>
    {
        public SaveInstallationInformation(IStepGroup parent, Group group, Configuration.Actions.UpdateWindowsRegistry action, Parameter.Enums.SetupMode setupMode)
            : base(parent, group, action, setupMode)
        {
            this.ResetProgress(1);
        }

        public override void Execute()
        {
            this.ResetProgress(1);

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                AddSystemInformation();
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                RemoveSystemInformation();
            }
        }

        public override void Undo()
        {
            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                UninstallArtefacts();
            }
        }

        public void AddSystemInformation()
        {
            this.IncrementProgress("Adicionando registros do painel de controle");

            if (SetupMainFactory.GetInstance().Parameter.IsInstalled)
            {
                if (this.IsStopped())
                    return;

                WindowsRegistry.InstalledInformation information = new WindowsRegistry.InstalledInformation();

                SystemInfo system = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo;

                string setupFolder = Path.Combine(SetupMainFactory.GetInstance().Parameter.InstallationPath, system.Id) + @"\Setup-v" + system.Version.Major;

                information.DisplayName = system.Description;
                information.InstallSource = SetupMainFactory.GetInstance().Parameter.InstalationSource;
                information.InstallLocation = SetupMainFactory.GetInstance().Parameter.InstallationPath;
                information.DisplayIcon = Path.Combine(setupFolder, system.Id) + ".ico";
                information.UninstallString = Path.Combine(setupFolder, "SetupUninstall.exe");
                information.ParametersFilePath = SetupMainFactory.GetInstance().Parameter.ParametersFilePath;
                information.DisplayVersion = system.Version.ToString();

                information.NoModify = false;
                information.NoRemove = false;
                information.NoRepair = false;

                this.AddUsedBy(system.ToString());

                PSE.Deployment.Util.WindowsRegistry.AddInstalledInformation(system.ToString(), information);

                CreateSubKeys();
            }
        }

        public void RemoveSystemInformation()
        {
            this.IncrementProgress("Removendo registros do painel de controle");

            if (!SetupMainFactory.GetInstance().Parameter.IsInstalled)
            {
                if (this.IsStopped())
                    return;

                PSE.Deployment.Util.WindowsRegistry.RemoveInstalledInformation(SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.ToString());
            }
        }

        protected override void UninstallArtefact(string artefactName)
        {
            PSE.Deployment.Util.WindowsRegistry.RemoveInstalledInformation(artefactName);
        }

        public void CreateSubKeys()
        {
            string key = WindowsRegistry.REGISTRY_UNINSTALL_PATH + SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.ToString();
            string keyModules = "Modules";

            Microsoft.Win32.RegistryKey systemKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(key);

            if (systemKey != null && systemKey.OpenSubKey(keyModules) != null)
            {
                Microsoft.Win32.Registry.LocalMachine.DeleteSubKeyTree(key + @"\" + keyModules);
            }

            var modules = (from g in SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Groups.SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Distinct(new GroupComparer())
                           where (g.Installed == true)
                           where !string.IsNullOrEmpty(g.Module.Name)
                           select new { g.Module.Id, g.Module.Name, g.Layers }).Distinct();

            foreach (var module in modules)
            {
                ModuleVersion installedModuleVersion = SetupMainFactory.GetInstance().Parameter.Versions.Find(v => v.Id == module.Id);
                                
                if (installedModuleVersion != null)
                {
                    Microsoft.Win32.RegistryKey subKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(key + @"\" + keyModules + @"\" + installedModuleVersion.Id);
                    subKey.SetValue("Version", installedModuleVersion.Version.ToString());
                    subKey.SetValue("ModuleName", installedModuleVersion.Name);

                    foreach (var layer in module.Layers)
                    {
                        Microsoft.Win32.RegistryKey subKeyLayer = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(key + @"\" + keyModules + @"\" + installedModuleVersion.Id + @"\" + layer.ToString());

                        var installedLayerVersion = SetupMainFactory.GetInstance().Parameter.Versions.Find(v => v.Id == module.Id).Layers.Find(l => l.Layer == layer);

                        if (installedLayerVersion != null)
                        {
                            subKeyLayer.SetValue("Version", installedLayerVersion.Version);
                        }
                    }
                }
            }
        }
    }
}
